package com.unism.unisdk.core;

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.Proxy;
import java.util.LinkedHashSet;
import java.util.Set;

import com.unism.unisdk.common.OpenService;
import com.unism.unisdk.common.SdkInitException;
import com.unism.unisdk.common.ServiceNotExistException;
import com.unism.unisdk.common.enumObj.Protocol;
import com.unism.unisdk.core.transport.OpenServiceProxy;
import com.unism.unisdk.core.transport.invoke.HttpFlowControlInvoke;
import com.unism.unisdk.core.transport.invoke.RemoteInvoke;
import com.unism.unisdk.core.utils.PackageScan;
import com.unism.unisdk.core.utils.StringUtils;
/**
 * 开放api服务工程,统一管理资源的初始化和接口调用
 * @author liuc
 *
 */
public class ServiceFactory implements Closeable {
	private static ServiceFactory serviceFactory;
	private Object serviceProxy;
	private Set<Class<?>> apiServiceSet;
	private RemoteInvoke remoteInvoke;

	private ServiceFactory(DefaultConfig defaultConfig) throws SdkInitException {
		this.apiServiceSet = scanService(defaultConfig.getApiBasePackage());
		if (this.apiServiceSet.size() == 0) {
			throw new SdkInitException("在包[" + defaultConfig.getApiBasePackage() + "]下未扫描到任何平台API");
		}
		Class[] apiServices = new Class[this.apiServiceSet.size()];
		this.apiServiceSet.toArray(apiServices);
		if ((defaultConfig.getFolwControl() != null) && (defaultConfig.getFolwControl().getIsUse()))
			this.remoteInvoke = new HttpFlowControlInvoke(defaultConfig, 1);
		setInvokeByProtocol(defaultConfig);
		this.serviceProxy = Proxy.newProxyInstance(ServiceFactory.class.getClassLoader(), apiServices,
				new OpenServiceProxy(this.apiServiceSet, defaultConfig, this.remoteInvoke));
	}

	private void setInvokeByProtocol(DefaultConfig defaultConfig) throws SdkInitException {
		// TODO Auto-generated method stub
		if(defaultConfig.getProtocol()!=null){
			switch(defaultConfig.getProtocol()){
				case HTTP:
					this.remoteInvoke = new HttpFlowControlInvoke(defaultConfig,1);
					break;
				case JRMP:
					throw new SdkInitException("初始化SDK失败,当前协议暂不支持");
				default:
					this.remoteInvoke = new HttpFlowControlInvoke(defaultConfig,1);
					break;
			}
		}
	}
	public static final synchronized ServiceFactory getInstance() throws SdkInitException {
		if (serviceFactory != null) {
			return serviceFactory;
		}
		return getInstance(new DefaultConfig());
	}
	public static final synchronized ServiceFactory getInstance(DefaultConfig defaultConfig) throws SdkInitException {
		if (defaultConfig == null) {
			defaultConfig = new DefaultConfig();
		}
		if ((StringUtils.isEmpty(defaultConfig.getApiBasePackage()))
				|| (StringUtils.isEmpty(defaultConfig.getApiDomain()))) {
			throw new SdkInitException("初始化失败,配置信息不允许为空");
		}
		if ((defaultConfig.getFolwControl().getIsUse()) && (defaultConfig.getFolwControl().getMaxQpm() > 24000)) {
			throw new SdkInitException("初始化SDK失败,最大QPM不允许超过24000");
		}
		if (serviceFactory == null) {
			serviceFactory = new ServiceFactory(defaultConfig);
		}
		return serviceFactory;
	}

	@SuppressWarnings("unchecked")
	public <T> T getOpenService(Class<T> clazz) throws ServiceNotExistException {
		if (!this.apiServiceSet.contains(clazz)) {
			throw new ServiceNotExistException("平台SDK不支持API: " + clazz.getCanonicalName());
		}
		return (T) this.serviceProxy;
	}
    /**
     * 扫描指定包下的所有添加注解的类(只有实现@OpenService注解才有效)
     * @param openApiBasePackage
     * @return
     */
	private Set<Class<?>> scanService(String openApiBasePackage) {
		Set<Class<?>> result = new LinkedHashSet<Class<?>>();
		Set<Class<?>> classes = PackageScan.scan(openApiBasePackage);
		for (Class<?> clazz : classes) {
			OpenService o = (OpenService) clazz.getAnnotation(OpenService.class);
			if ((o != null) && (clazz.isInterface())) {
				result.add(clazz);
			}
		}
		return result;
	}
   /**
    * 关闭远程调用
    */
	public void close() throws IOException {
		this.remoteInvoke.close();
	}
}